import random
import time
from datetime import datetime
import paramiko
import schedule
from openpyxl.workbook import Workbook

from logger.logger import Log
import api.config


# 用于测试Flash存储器的读写 -- ssh连接
# @AUTHOR -- 陈选 -- 2024-04-18
class flashConnect:
    def start(self):
        try:
            # ssh连接
            self.ssh.load_system_host_keys()
            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh.connect(self.connect_ip, port=self.connect_port, username=self.connect_user,
                             password=self.connect_pwd)
            self.is_connect = True
            self.invoke = self.ssh.invoke_shell()

            a = api.config.Config.arg['TestCase']['FlashTime']
            # 当前时间加上['TestCase']['FlashTime']的秒数
            while time.time() < self.end_time + a + (a % 60) * 3 + 10:
                self.perform_file_io_and_record_data()
                schedule.run_pending()
                time.sleep(600)
            # 运行['TestCase']['FlashTime']后输出 Excel 表格
            self.write_to_excel()
        except Exception as e:
            Log.logger.info(f"发现异常: {e}")
            Log.logger.error(f"发现异常: {e}")
            self.FlashStatus["time"] = get_time()
            self.FlashStatus["result"] = "Failed"
            self.FlashStatus["detail"] = str(e) + ",检测到Socket is closed，执行重新登陆选项"
            result = self.FlashStatus.get("result", "Failed eee")
            detail = self.FlashStatus.get("detail", "")
            time_now = get_time()
            self.recorded_data.append([time_now, result, detail])
            # 如果发生异常，尝试重新连接并继续执行
            self.sshLogin()
            self.start()
        finally:
            # 清理和保存数据
            self.write_to_excel()

    def perform_file_io_and_record_data(self):
        print("失败次数")
        print(self.FlashFailedTime)
        self.sendFlash(self.a)
        time_now = get_time()
        result = self.FlashStatus.get("result", "Failed")
        detail = self.FlashStatus.get("detail", "")
        self.a += 1
        # 记录数据到列表中
        self.recorded_data.append([time_now, result, detail])

    def sshLogin(self, retries=0):
        try:
            # 关闭之前的连接
            if self.ssh is not None:
                self.ssh.close()
                Log.logger.info("关闭之前的SSH连接")
        except Exception as e:
            Log.logger.error(f"关闭SSH连接时发生异常: {e}")
        try:
            # 创建新的SSH连接
            self.ssh = paramiko.SSHClient()
            Log.logger.info("创建新的SSH连接")
            self.ssh.load_system_host_keys()
            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh.connect(self.connect_ip, port=self.connect_port, username=self.connect_user,
                             password=self.connect_pwd, timeout=600)
            self.is_connect = True
            self.invoke = self.ssh.invoke_shell()
            Log.logger.info("成功建立SSH连接")
        except Exception as e:
            if retries < 20:
                Log.logger.error(f"尝试重新登录时发生异常: {e}. 尝试重新登录 ({retries + 1}/20)")
                self.FlashStatus["time"] = get_time()
                self.FlashStatus["result"] = "Failed"
                self.FlashFailedTime += 1
                self.FlashStatus["detail"] = "尝试重新登录时发生异常,尝试重新登录" + str(self.invoke.recv(5000).decode('utf-8'))
                result = self.FlashStatus.get("result", "Failed")
                detail = self.FlashStatus.get("detail", "")
                time_now = get_time()
                self.recorded_data.append([time_now, result, detail])
                self.sshLogin(retries=retries + 1)
            else:
                Log.logger.error(f"尝试重新登录时发生异常: {e}. 已达到最大重试次数，放弃登录")

    def sendFlash(self, a):
        try:
            Log.logger.info(str(get_time()))
            self.invoke.send(("echo " + str(a) + " > /customer/flash_test.txt" + '\n').encode())
            self.invoke.send(("cat /customer/flash_test.txt" + '\n').encode())
            time.sleep(2)
            outputOfEcho = self.invoke.recv(5000).decode('utf-8')
            Log.logger.info(outputOfEcho)
            if str(a) in outputOfEcho.strip():
                self.FlashStatus["time"] = get_time()
                self.FlashStatus["result"] = "PASS"
                self.FlashStatus["detail"] = ""
                self.FlashPassTime += 1
                Log.logger.info("PASS")
                Log.logger.error(str(get_time()))
            else:
                self.FlashStatus["time"] = get_time()
                self.FlashStatus["result"] = "Failed"
                self.FlashFailedTime += 1
                self.FlashStatus["detail"] = "数据不一，写入操作失败" + str(self.invoke.recv(5000).decode('utf-8'))
                result = self.FlashStatus.get("result", "Failed")
                detail = self.FlashStatus.get("detail", "")
                # time_now = get_time()
                # self.recorded_data.append([time_now, result, detail])
                Log.logger.info("Failed")
                Log.logger.error(str(get_time()))
        except Exception as e:
            Log.logger.info(get_time())
            Log.logger.error(get_time())
            Log.logger.info(f"发送读写指令时发生异常: {e}")
            Log.logger.error(f"发送读写指令时发生异常: {e}")
            if "Socket is closed" in str(e) or "connect" in str(e):
                # 处理异常并尝试重新登录
                time.sleep(2)
                self.FlashStatus["result"] = "Failed"
                self.FlashStatus["detail"] = str(e) + ",检测到Socket is closed，执行重新登陆选项"
                self.FlashFailedTime += 1
                Log.logger.info("Failed e1")
                Log.logger.error(str(get_time()))
                self.sshLogin()
            else:
                self.FlashStatus["result"] = "Failed"
                self.FlashStatus["detail"] = str(e)  # 添加异常详情
                self.FlashFailedTime += 1
                Log.logger.info("Failed e2")
                result = self.FlashStatus.get("result", "Failed")
                detail = self.FlashStatus.get("detail", "")
                time_now = get_time()
                self.recorded_data.append([time_now, result, detail])
                Log.logger.error(str(get_time()))

    def write_to_excel(self):
        try:
            # 创建一个新的工作簿
            wb = Workbook()
            # 选择活动工作表
            ws = wb.active
            # 设置第一列和第二列的宽度
            ws.column_dimensions['A'].width = 20  # 设置第一列宽度为20
            ws.column_dimensions['B'].width = 20  # 设置第二列宽度为20
            ws.column_dimensions['A'].height = 20  # 设置第一列宽度为20
            ws.column_dimensions['B'].height = 20  # 设置第二列宽度为20
            # 写入数据
            ws.append(['Flash读写时间', '测试结果'])
            for data_row in self.recorded_data:
                ws.append(data_row)
            # 保存工作簿
            pass_rate = (self.FlashPassTime / (self.FlashPassTime + self.FlashFailedTime)) * 100
            ws.append(['测试总次数', self.FlashPassTime + self.FlashFailedTime])
            ws.append(['测试通过次数', self.FlashPassTime])
            ws.append(['测试失败次数', self.FlashFailedTime])
            ws.append(['测试通过率:', '{:.2f}%'.format(pass_rate)])  # 保留两位小数
            current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
            wb.save(f'report/{current_time}_Flash.xlsx')
        except Exception as e:
            Log.logger.info(f"写入 Excel 表格时发生异常: {e}")
            Log.logger.error(f"写入 Excel 表格时发生异常: {e}")

    def close(self):
        if self.is_ssh_con:
            self.ssh.close()
        else:
            self.serial.close()

    def __init__(self):
        self.is_connect = False
        self.pid = None
        self.pid_kill = True
        self.data = str()
        self.serial = None
        self.invoke = None
        self.end_str = api.config.Config.arg['TestCase']['endstr']
        self.exepath = api.config.Config.arg['TestCase']['exepath']
        self.exe = api.config.Config.arg['TestCase']['exe']
        self.FlashStatus = {}
        self.FlashPassTime = 0
        self.end_time = time.time()
        self.FlashFailedTime = 0
        self.recorded_data = []
        self.i = 0
        self.max_retries = 10
        self.a = random.randint(10086, 6666666)
        self.is_ssh_con = True if api.config.Config.arg['Gateway']['Connect'] == 'SSH' else False
        if self.is_ssh_con:
            self.ssh = paramiko.SSHClient()
            self.connect_ip = api.config.Config.arg['Gateway']['IPAddress']
            self.connect_user = api.config.Config.arg['Gateway']['Username']
            self.connect_pwd = api.config.Config.arg['Gateway']['Password']
            self.connect_port = api.config.Config.arg['Gateway']['Port']
        else:
            self.login_by_serial = False
            self.read_serial_data = False
            # 串行端口的名称或者设备文件名
            self.serial_port = api.config.Config.arg['Gateway']['SerialPort']
            # 波特率
            self.serial_bitrate = int(api.config.Config.arg['Gateway']['SerialBitrate'])


def get_time() -> str:
    return time.strftime("%Y%m%d_%H_%M_%S", time.localtime())
